package cn.txun.csmall.commons.ex.handler;



import cn.txun.csmall.commons.ex.ServiceException;
import cn.txun.csmall.commons.web.ServiceCode;
import cn.txun.csmall.commons.web.JsonResult;


import lombok.extern.slf4j.Slf4j;
import org.springframework.security.access.AccessDeniedException;
import org.springframework.security.authentication.BadCredentialsException;
import org.springframework.security.authentication.DisabledException;
import org.springframework.security.authentication.InternalAuthenticationServiceException;
import org.springframework.security.core.AuthenticationException;
import org.springframework.validation.BindException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;

import javax.validation.ConstraintViolation;
import javax.validation.ConstraintViolationException;
import java.util.Set;

/**
 * 处理类别相关请求的控制器类
 *
 * @author sunyu java@txun.cn
 * @version 0.0.1
 */
@Slf4j
//全局异常处理类，添加此注解，此类中每个处理异常的方法，都作用于项目中的每个处理请求的方法
@RestControllerAdvice
public class GlobalExceptionHandler {

    GlobalExceptionHandler(){
        log.debug("创建GlobalExceptionHandler对象");
    }

    @ExceptionHandler
    public JsonResult handlerServiceException(ServiceException e){
        log.warn("程序运行过程中出现了ServiceException,将统一处理");
        log.warn("异常", e);
       /* JsonResult jsonResult = new JsonResult();
        jsonResult.setState(2);
        jsonResult.setMessage(e.getMessage());*/
        //return new JsonResult().setMessage(e.getMessage()).setState(2);
        return JsonResult.fail(ServiceCode.ERR_CONFLICT,e.getMessage());
    }



    @ExceptionHandler
    public JsonResult HandlerConstraintViolationException(ConstraintViolationException e) {
        log.warn("程序运行过程中出现了ConstraintViolationException,将统一处理");
        log.warn("异常", e);
        String message = null;
        Set<ConstraintViolation<?>> constraintViolations =  e.getConstraintViolations();
        for(ConstraintViolation c:constraintViolations){
            message = c.getMessage();
        }
        /*JsonResult jsonResult = new JsonResult();
        jsonResult.setState(3);
        jsonResult.setMessage(message);*/
        //return new JsonResult().setMessage(message).setState(3);
        return JsonResult.fail(ServiceCode.ERR_BAD_REQUEST,message);
    }


    @ExceptionHandler
    public JsonResult HandlerBindException(BindException e){
        log.warn("程序运行过程中出现了BindException,将统一处理");
        log.warn("异常",e);
        //【解决方案-1】，使用一个字符串表示1个错误
        //获取错误信息
        String message = e.getFieldError().getDefaultMessage();
      /*  JsonResult jsonResult = new JsonResult();
        jsonResult.setState(4);
        jsonResult.setMessage(message);*/
        //return new JsonResult().setMessage(message).setState(4);
        return JsonResult.fail(ServiceCode.ERR_BAD_REQUEST,message);

        //【解决方案-2】使用一个字符串表示全部错误信息
        /*  StringJoiner joiner = new StringJoiner(",","请求参数错误，","!");
        List<FieldError> fieldErrors = e.getFieldErrors();
        for(FieldError fieldError:fieldErrors){
            String message = fieldError.getDefaultMessage();
            joiner.add(message);
        }
        return joiner.toString();*/

       /* //【解决方案-3】使用集合表示多个错误信息，需要将当前方法的返回值类型声明为对象的集合类型
        List<String> messages = new ArrayList<>();
        List<FieldError> fieldErrors = e.getFieldErrors();
        for(FieldError fieldError:fieldErrors){
            String message = fieldError.getDefaultMessage();
            messages.add(message);
        }
        return messages;*/
    }

   /* @ExceptionHandler
    public String handlerNullPointerException(NullPointerException e){
        log.warn("程序运行过程中出现了NullPointerException,将统一处理");
        log.warn("异常信息:{}",e.getMessage());
        return e.getMessage();
    }
    @ExceptionHandler
    public String handlerRuntimeException(RuntimeException e){
        log.warn("程序运行过程中出现了RuntimeException,将统一处理");
        log.warn("异常信息:{}",e.getMessage());
        return e.getMessage();
    }*/
    //如果@ExceptionHandler没有配置参数，则以方法参数的异常类型为主，来处理异常
    //如果@ExceptionHandler配置参数，则只处理此配置中的异常
   @ExceptionHandler({
           BadCredentialsException.class,
           InternalAuthenticationServiceException.class
   })
   public JsonResult handlerAuthenticationException(AuthenticationException e){
       log.warn("程序运行过程中出现了AuthenticationException,将统一处理");
       log.warn("异常信息",e);
       String message = "登录失败，用户名或者密码错误";
       return JsonResult.fail(ServiceCode.ERR_UNAUTHORIZED,message);
   }

    @ExceptionHandler
    public JsonResult handlerDisabledException(DisabledException e){
        log.warn("程序运行过程中出现了DisabledException,将统一处理");
        log.warn("异常信息",e);
        String message = "登录失败，用户失效";
        return JsonResult.fail(ServiceCode.ERR_UNAUTHORIZED_DISABLE,message);
    }

    @ExceptionHandler
    public JsonResult handlerAccessDeniedException(AccessDeniedException e){
        log.warn("程序运行过程中出现了AccessDeniedException,将统一处理");
        log.warn("异常信息",e);
        String message = "您当前登录的账号无权限，禁止访问";
        return JsonResult.fail(ServiceCode.ERR_FORBIDDEN,message);
    }

    @ExceptionHandler
    public JsonResult handlerThrowable(Throwable e){
        log.warn("程序运行过程中出现了Throwable,将统一处理");
        log.warn("异常信息",e); //替换e.printStackTrace()，在项目上线时，禁止使用e.printStackTrace
                              //他们效果相同，注意，第一个参数不用{}进行占位
        String message = "服务器忙，请稍后再试！【如果是开发过程中，看到此异常，应该检查服务器的控制台，分析异常，" +
                "并在全局异常处理中添加对应的处理方法】";
        //return new JsonResult().setMessage(message).setState(9999);
        return JsonResult.fail(ServiceCode.ERR_UNKNOWN,message);
    }
}
